package com.rockbb.common.sso.session;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;

import org.apache.log4j.Logger;

import com.rockbb.common.utilities.security.StringDigest;

public class MemcachedSessionMap implements SessionMap
{

	private static Logger logger = Logger.getLogger(MemcachedSessionMap.class);
	private Set<String> keys;

	public Collection<String> getKeys()
	{
		return keys;
	}

	public List<Session> getSessions(Collection<String> keysList)
	{
		logger.debug("get sessions with " + keysList.size() + " keys");
		List<Session> sessions = new ArrayList<Session>();
		if (keysList != null && keysList.size() > 0)
		{
			String[] keyArray = keysList.toArray(new String[]{});
			Object[] objs = MemCachedProxy.getArray(keyArray);

			if (objs != null && objs.length > 0)
			{
				for (Object obj: objs)
				{
					if (obj instanceof Session && obj != null)
						sessions.add((Session)obj);
					else
						logger.debug("invalid session");
				}
			}
		}
		logger.debug("returned " + sessions.size() + " sessions");
		return sessions;
	}

	public void initialise()
	{
		keys = new HashSet<String>();
	}

	public void reset()
	{
		keys.clear();
		MemCachedProxy.flush();
	}

	public void put(String sid, Session session)
	{
		logger.debug("putSession: " + sid);
		keys.add(sid);
		if (MemCachedProxy.exists(sid))
		{
			MemCachedProxy.replace(sid, session);
		}
		else
		{
			MemCachedProxy.set(sid, session);
		}
	}

	public int size()
	{
		return keys.size();
	}

	public Session get(String sid)
	{
		if (sid==null || sid.length()==0) return null;

		if (!MemCachedProxy.exists(sid))
		{
			logger.debug("return null on non-exist sid: " + sid);
			remove(sid);
			return null;
		}

		Object obj = MemCachedProxy.get(sid);
		if (obj == null || !(obj instanceof Session))
		{
			logger.debug("return null on expired session: " + sid);
			remove(sid);
			return null;
		}
		else
		{
			if (!keys.contains(sid))
			{
				keys.add(sid);
			}
			return (Session) obj;
		}
	}

	public Session createSession(boolean persistent)
	{
		// TODO Auto-generated method stub
		return null;
	}

	public Session createSession(long uuid, String browser, String ip, boolean persistent)
	{
		logger.debug("createSession: " + uuid + ", " + ip);
		Session session = new Session();
		session.setSession_uuid(uuid);
		session.setSession_start(System.currentTimeMillis());
		session.setSession_time(System.currentTimeMillis());
		session.setSession_ip(ip);
		session.setSession_secure(0);
		session.setSession_browser(browser);
		session.setSession_autologin(SessionConstants.SESSION_AUTOLOGIN_OFF);
		session.setSession_token(StringDigest.unique_id());
		if (persistent)
		{
			put(session.getSession_id(), session);
		}
		return session;
	}

	public void resetSession(String sid)
	{
		logger.debug("resetSession: " + sid);
		Session session = get(sid);
		if (session != null)
		{
			session.setSession_uuid(SessionConstants.USER_UID_ANONYMOUS);
			session.setSession_start(System.currentTimeMillis());
			session.setSession_time(System.currentTimeMillis());
			session.setSession_secure(0);
			session.setSession_autologin(SessionConstants.SESSION_AUTOLOGIN_OFF);
			session.setSession_token(StringDigest.unique_id());
			put(sid, session);
		}
	}

	public void resetSessionToken(String sid)
	{
		logger.debug("resetSessionToken: " + sid);
		Session session = get(sid);
		if (session != null)
		{
			session.setSession_time(System.currentTimeMillis());
			session.setSession_token(StringDigest.unique_id());
			put(sid, session);
		}
	}

	public void renewSession(String sid, String ip)
	{
		logger.debug("updateSessionTime: " + sid);
		Session session = get(sid);
		if (session != null)
		{
			session.setSession_time(System.currentTimeMillis());
			session.setSession_ip(ip);
			put(sid, session);
		}
	}

	public void updateSessionUser(String sid, long uuid, int autologin)
	{
		logger.debug("updateSessionUser: " + sid + ", uuid:" + uuid);
		Session session = get(sid);
		if (session != null)
		{
			session.setSession_time(System.currentTimeMillis());
			session.setSession_uuid(uuid);
			session.setSession_autologin(autologin);
			put(sid, session);
		}
	}

	public void expireSession(String sid)
	{
		logger.debug("expireSession: " + sid);
		Session session = get(sid);
		if (session != null)
		{
			session.setSession_time(session.getSession_time() - SessionConstants.SESSION_EXPIRE_MAX*1000);
			put(sid, session);
		}
	}

	public void remove(String sid)
	{
		logger.debug("removeSession: " + sid);
		if (MemCachedProxy.exists(sid))
			MemCachedProxy.delete(sid);
		try
		{
			keys.remove(sid);
		}
		catch (Exception e)
		{
			// Do nothing
		}
	}

	public int cleanUp()
	{
		logger.debug("cleanUp");
		List<String> expired = new ArrayList<String>();
		Iterator<String> iter = keys.iterator();
		while (iter.hasNext()) {
			String sid = iter.next();
		    Session session = get(sid);
		    if (session == null || session.is_expired()) {
		    	expired.add(sid);
		    }
		}
		int cleaned = expired.size();
		for (int i=0; i<cleaned; i++) {
			remove(expired.get(i));
		}
		expired = null;
		logger.info("Sessions: " + keys.size() + " cleand: " + cleaned);
		return cleaned;
	}
}
